package com.yc.sole.framework.web;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import com.yc.sole.framework.context.SecureContextHolder;
import com.yc.sole.framework.exception.BaseException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Objects;

/**
 * 自定义权限解析
 *
 * @author yizuomin
 */
@Slf4j
@Aspect
@RequiredArgsConstructor
@Component
@Order(2)
public class PreAuthAspect {

    private final SecurityAuthenticator securityAuthenticator;

    @Around("@annotation(com.yc.sole.framework.web.PreAuth)")
    public Object aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable {
        Signature signature = joinPoint.getSignature();
        MethodSignature msg = (MethodSignature) signature;
        Object target = joinPoint.getTarget();
        Method method = target.getClass().getMethod(msg.getName(), msg.getParameterTypes());
        //通过方法获取注解
        PreAuth annotation = method.getAnnotation(PreAuth.class);
        BaseUserInfo baseUserInfo = this.checkPermissions(annotation);
        if (Objects.nonNull(baseUserInfo)) {
            log.info("username：【{}】,userId：【{}】,permission:【{}】,description:【{}】", baseUserInfo.getUsername(), baseUserInfo.getId(), annotation.value(), annotation.description());
        } else {
            log.info("permission:【{}】,description:【{}】", annotation.value(), annotation.description());
        }
        return joinPoint.proceed();
    }

    @Around("@within(com.yc.sole.framework.web.PreAuth)")
    public Object aroundClass(ProceedingJoinPoint joinPoint) throws Throwable {
        Object target = joinPoint.getTarget();
        //通过方法获取注解
        PreAuth annotation = target.getClass().getAnnotation(PreAuth.class);
        BaseUserInfo baseUserInfo = this.checkPermissions(annotation);
        if (Objects.nonNull(baseUserInfo)) {
            log.info("username：【{}】,userId：【{}】,permission:【{}】,description:【{}】", baseUserInfo.getUsername(), baseUserInfo.getId(), annotation.value(), annotation.description());
        } else {
            log.info("permission:【{}】,description:【{}】", annotation.value(), annotation.description());
        }
        return joinPoint.proceed();
    }

    /**
     * 校验权限
     *
     * @param annotation
     */
    private BaseUserInfo checkPermissions(PreAuth annotation) {
        if (!securityAuthenticator.enableAuthentication() || !annotation.check()) {
            return null;
        }
        BaseUserInfo userInfo = SecureContextHolder.getUserInfo();
        if (Objects.isNull(userInfo)) {
            throw new BaseException("请登录");
        }
        Collection<String> permissions = userInfo.getPermissions();
        if (CollUtil.isEmpty(permissions)) {
            throw new BaseException("对不起，您没有操作权限");
        }
        boolean hasPermission = permissions.stream().anyMatch(permission -> {
            String[] checkPermission = annotation.value();
            return CharSequenceUtil.equalsAnyIgnoreCase(permission, checkPermission);
        });
        if (!hasPermission) {
            log.warn("no permission!!!username：【{}】,userId：【{}】,permission:【{}】,description:【{}】", userInfo.getUsername(), userInfo.getId(), annotation.value(), annotation.description());
            throw new BaseException("对不起，您没有操作权限");
        }
        return userInfo;
    }
}
